/**
 * Copyright 2006-2015 handu.com
 * <p/>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p/>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p/>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.iepacj.nio.channel;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;

public class ChannelCopy {

    public static void main(String[] args) throws IOException {

        ReadableByteChannel source = Channels.newChannel(System.in);

        WritableByteChannel dest = Channels.newChannel(System.out);

        channelCopy1(source, dest);

    }

    private static void channelCopy1(ReadableByteChannel source, WritableByteChannel dest) throws IOException {

        ByteBuffer buf = ByteBuffer.allocate(16 * 1024);
        while (source.read(buf) != -1) {
            buf.flip();
            // 写入到目标channel, 可能会阻塞
            dest.write(buf);
            /**
             *  channel是一种非阻塞io操作，write操作并不能一次将buffer中的数据全部写入
             *  到指定的channel中去，但如果一次写不完的话，那么第二次再读取的时候
             *  我们就要将 position = limit, limit = capacity, 然后再读取
             *  不然第二次读取的数据会把第一次没有write完的数据覆盖掉。等设置后第二次读取完成后
             *  我们还是要向channel中write数据，然后这次写入数据还要从上一次没有写完的地方开始写
             *  我们还要将position 还原到上一步记录的地方, 然后将limit设置成
             *  最后一次 position 的位置，这样做在复杂，因此提供了一个compact操作，我们在 write 后
             *  执行 buffer.compact()将没有发出的数据复制到buffer的开始位置
             *  posittion = limit-position,limit = capacity
             *  这样在下一次read(buffer)的时候，数据就会继续添加到缓冲的后面了
             *  因此标准的从一个channel 的数据到另一个 channel 的操作是这样的
             */
            buf.compact();
        }
        buf.flip();
        // 确保buf确实是清空了
        while (buf.hasRemaining()) {
            dest.write(buf);
        }

    }

}
